#include "stm32f10x.h"                  // Device header

// PWM 频率 和 占空比需要关注的3个参数
#define ARR 20000 - 1     /*<!-- PWM 分辨率为  1 / (ARR + 1)              -->*/
#define PSC 72  - 1       /*<!-- PWM 频率为 72MHz / (PSC + 1) / (ARR + 1) -->*/
#define CCR 0             /*<!-- 占空比为 CCR / (ARR + 1)                 -->*/

#define PA15_REMAPING 0

void PWM_Init(void)
{
	// 第一步: RCC 开启时钟, 开启 GPIOA 和 TIM2 的时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

#ifdef PA15_REMAPING
	
	// 需要引脚重新映射, 由原先的 PA0 改为 PA15 输出 PWM 波形, 则需要开启 AFIO 时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	
	// 引脚重映射配置 : 参考文档 ”STM32F10xxx 参考手册 P119“ 
	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);
	
	// 关闭 PA15、PB3、PB4 作为 JDTI 作为调试端口的服用
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
	
#endif
	 
	// 第二步: 配置 TIM 的时钟源 和 时基单元都配置好
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;        // 这个是外部时钟的时候，消抖采样的频率对内部时钟的分频, 随便配置一个即可。
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;    // 向上计数
	TIM_TimeBaseInitStruct.TIM_Period = ARR;                  // 计数重装值, ARR
	TIM_TimeBaseInitStruct.TIM_Prescaler = PSC;               // 预分频, PSC, 注意 PSC 和 ARR 都要在 0~65535 之间, 公式: 
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;               // 高级定时器才会使用, 我们不用管
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);

	// 第三步: 配置输出比较单元: 其中包括 CCR 的值, 输出 比较模式, 极性选择, 输出使能这些参数
	// PA0 口对应输出比较通道
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);                         // 使用默认初始值初始化结构体
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;               // 输出比较模式
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;       // 输出的比较极性, 高极性 即 不翻转, REF 波形直接输出
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   // 输出使能
	TIM_OCInitStructure.TIM_Pulse = CCR;                            // CCR
	TIM_OC2Init(TIM2, &TIM_OCInitStructure);                        // Init OC2

	// 第四步: 配置 GPIO, 初始化为复用推挽输出的配置, 指定 PWM 通道和指定引脚是一一对应的关系
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                 // 复用推挽输出, 高低电平均具有驱动能力, 且高低电平的来源不来自输出数据寄存器, 而是片上外设.

#if PA15_REMAPING
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;                      // Pin15 脚为 TIM2 的 CCH1 通道
#else
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;                       // Pin1 脚为 TIM2 的 CCH2 通道
#endif
	
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	// 第五步: 运行控制寄存器配置, 启动计数器, 就能开始输出 PWM 波形了
	TIM_Cmd(TIM2, ENABLE);
}

// 动态的改变CCR的值, 进而改变占空比
void PWM_SetCompare2(uint16_t Compare)
{
	TIM_SetCompare2(TIM2, Compare);
}